﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.SecurityControl;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;
using Wyn.PMS.Entity.DataAccess;
using System.Threading.Tasks;

namespace Wyn.PMS.Common.NightAudit
{
    public class RoomCountCache
    {
        #region ☆ -------- 初始化做预备 -------- ☆

        /// <summary>
        /// 需要更新房量的队列 string：hotelId,Datetime:更新版本时间
        /// </summary>
        private IDictionary<string, DateTime> _updateQueue = new Dictionary<string, DateTime>();

        /// <summary>
        /// 房量缓存调整[string:hotelId[string orderId]]
        /// </summary>
        private IDictionary<string, IDictionary<string, RoomOccupy>> _hotelOccupies =new Dictionary<string, IDictionary<string, RoomOccupy>>();
        
        private static volatile RoomCountCache _instance;

        private static readonly object _lock = new object();

        /// <summary>
        /// 抢救数据间隔秒数
        /// </summary>
        public const int RESCUE_CYCLE=10; 
        
        private RoomCountCache(){}

        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        /// <summary>
        /// 只读容器
        /// </summary>
        private ReadonlyDictionary<string, IDictionary<string,RoomOccupy>> _readonlyRoomOccupies;

        /// <summary>
        /// 酒店默认入住时间[需做成可配置]
        /// </summary>
        private const int DEFAULT_STARTDATE_HOUR = 23;
        /// <summary>
        /// 酒店默认退房时间[需做成可配置]
        /// </summary>
        private const int DEFAULT_ENDDATE_HOUR = 12;

        public static RoomCountCache GetInstance()
        {
            if(_instance==null)
            {
                lock(_lock)
                {
                    if(_instance==null)
                    {
                        var rcc = new RoomCountCache();

                        rcc.InitCache();

                        _instance = rcc;

                        Thread.MemoryBarrier();
                    }
                }
            }
            return _instance;
        }

        #endregion

        #region ☆ -------- 内部处理过程 -------- ☆

        private void InitCache()
        {
            IRoomOccupyRepository roomOccupyRepository = container.Resolve<IRoomOccupyRepository>();
            
            var connections = DbContextService.GetAllConnectionString();

            try
            {
                foreach (var conn in connections)
                {
                    IList<RoomOccupy> occupies = null;

                    var transactionOptions = new System.Transactions.TransactionOptions();

                    transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

                    using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                    {
                        occupies = roomOccupyRepository.GetAllRoomOccupies(conn);

                        scope.Complete();
                    }

                    if (occupies != null && occupies.Count>0)
                    {
                        DateTime versionTime = occupies.Max(o => o.ModifiedTime);

                        _updateQueue.Add(conn, versionTime);

                        FillCache(occupies);
                    }

                }
            }catch(Exception error)
            {
                OperateLog.ErrorLog(DateTime.Now + "房量缓存初始化失败" + error);
            }
        }
        
        private void FillCache(IList<RoomOccupy> occupies)
        {
            IList<string> hotelIds = occupies.Select(o => o.HotelID).Distinct().ToList();

            IDictionary<string, IEnumerable<RoomOccupy>> hotelCountainer = new Dictionary<string, IEnumerable<RoomOccupy>>();

            foreach (var hotelId in hotelIds) 
            {
                //构建酒店房量缓存容器
                CreateCacheContainer(hotelId);

                IEnumerable<RoomOccupy> hotelOccupies = occupies.Where(o => o.HotelID == hotelId);

                hotelCountainer.Add(hotelId, hotelOccupies);            
            }

            //存入缓存
            Parallel.ForEach(hotelCountainer, (hotelOrders) => {
                foreach (var occupy in hotelOrders.Value) 
                {
                    if (_hotelOccupies[hotelOrders.Key].ContainsKey(occupy.OrderId))
                    {
                        _hotelOccupies[hotelOrders.Key].Remove(occupy.OrderId);
                    }
                    if (occupy.IsValid)
                    {
                        _hotelOccupies[hotelOrders.Key].Add(occupy.OrderId, occupy);
                    }
                }
            });

            WrapReadonlyOccupy();           
        }

        /// <summary>
        /// 打包只读房量
        /// </summary>
        private void WrapReadonlyOccupy() 
        {
            var dict = new Dictionary<string, IDictionary<string, RoomOccupy>>();

            foreach (var hotelId in _hotelOccupies.Keys) 
            {
                var subDict = new ReadonlyDictionary<string, RoomOccupy>(_hotelOccupies[hotelId]);

                dict.Add(hotelId, subDict);

                var readonlyOccupies = new ReadonlyDictionary<string, IDictionary<string, RoomOccupy>>(dict);

                _readonlyRoomOccupies = readonlyOccupies;
            }
        }

        private void CreateCacheContainer(string hotelId)
        {            
            if (!_hotelOccupies.ContainsKey(hotelId))
            {
                IDictionary<string, RoomOccupy> occupyContainer = new Dictionary<string, RoomOccupy>();

                _hotelOccupies.Add(hotelId, occupyContainer);
            }                     
        }

        public void Refresh()
        {
            //System.Diagnostics.Debug.WriteLine("刷新房量:" + DateTime.Now.ToString());
            try
            {
                BuildCache(null);

            }catch(Exception error)
            {

                OperateLog.ErrorLog(DateTime.Now + "房量缓存刷新失败", error);
                
            }
        }

        public void Rescue(int seconds)
        {
            //System.Diagnostics.Debug.WriteLine("修正房量:" + DateTime.Now.ToString());
            try
            {
                BuildCache(DateTime.Now.AddSeconds(seconds));

            }catch(Exception error)
            {

                OperateLog.ErrorLog(DateTime.Now + "房量缓存修正失败", error);
            }

        }

        private void BuildCache(DateTime? time)
        {
            IRoomOccupyRepository roomOccupyRepository = container.Resolve<IRoomOccupyRepository>();
            
            var keys= _updateQueue.Select(o => o.Key).ToList();
            
            foreach (var key in keys)
            {
                DateTime versionTime = time ?? _updateQueue[key];

                Expression<Func<RoomOccupy, bool>> exp = r => r.ModifiedTime > versionTime;
                //分库读取所有有效房控信息
                IList<RoomOccupy> occupies = null;

                var transactionOptions = new System.Transactions.TransactionOptions();

                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

                using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    occupies =roomOccupyRepository.GetRoomOccupies(key, exp);

                    scope.Complete();
                }

                if (occupies != null && occupies.Count > 0)
                {
                    FillCache(occupies);

                    _updateQueue[key] = occupies.Max(r => r.ModifiedTime);
                }
            }
        }
        
        #endregion

        #region ☆ -------- 外部调用服务 -------- ☆
        
        public IDictionary<string,IDictionary<string, RoomOccupy>> RoomOccupies
        {
            get
            {   
                return _readonlyRoomOccupies;
            }
        }

        /// <summary>
        /// 获取缓存房控
        /// </summary>
        /// <param name="hotelId">酒店编号</param>
        /// <param name="predicate"></param>
        /// <returns></returns>
        private IList<RoomOccupy> GetCacheOccupies(string hotelId, Func<RoomOccupy,bool> predicate)
        {
            if (_readonlyRoomOccupies == null||!_readonlyRoomOccupies.ContainsKey(hotelId))
                return new List<RoomOccupy>();

            var occupies = _readonlyRoomOccupies[hotelId].Values.Where(predicate).ToList();

            return occupies;
        }

        /// <summary>
        /// 获取一段时间内酒店所有房型的详细房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public Dictionary<DateTime, IEnumerable<RoomCount>> GetHotelRoomCount(string hotelId, DateTime beginDate, DateTime endDate)
        {
            if(beginDate>endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }

            DateTime startDate = beginDate.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId,exp);

            Dictionary<DateTime, IEnumerable<RoomCount>> hotelRoomCount =new Dictionary<DateTime, IEnumerable<RoomCount>>();
            
            while(endDate>startDate)
            {
                IList<RoomCount> counts = new List<RoomCount>();

                DateTime nextDate = startDate.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

                #region 填充房量

                foreach (var item in roomtypes)
                {
                    RoomType roomtype = item;

                    DateTime date = startDate;

                    var occupies = GetCacheOccupies(hotelId, o => o.RoomTypeID == roomtype.RoomTypeID
                                                    && o.StartDate < nextDate
                                                    && o.EndDate > date
                                                    && o.IsValid);

                    var count = BuildRoomCount(occupies, roomtype,startDate);

                    counts.Add(count);
                }

                #endregion

                hotelRoomCount.Add(startDate.Date, counts);

                startDate = startDate.AddDays(1);
            }

            return hotelRoomCount;
        }

        /// <summary>
        /// 获取一段时间内酒店所有房型大致可用房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public IEnumerable<RoomCount> GetUsableRoomCount(string hotelId,DateTime beginDate,DateTime endDate)
        {
            if (beginDate > endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }

            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId, exp);
            
            IList<RoomCount> counts = new List<RoomCount>();

            foreach (var item in roomtypes)
            {
                RoomType roomType = item;

                var count = GetRoomTypeCount(hotelId, roomType, beginDate, endDate);

                counts.Add(count);
            }

            return counts;
        }

        /// <summary>
        /// 获取一段时间内酒店某种房型可用房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypeId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public RoomCount GetRoomCount(string hotelId,string roomTypeId,DateTime beginDate,DateTime endDate)
        {
            if (beginDate > endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }
            
            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            RoomType roomtype = repositoryRoomTypes.Find(hotelId, hotelId, roomTypeId);

            return GetRoomTypeCount(hotelId, roomtype, beginDate, endDate);

        }

        private RoomCount GetRoomTypeCount(string hotelId, RoomType roomtype, DateTime beginDate, DateTime endDate)
        {
            if (beginDate.Date == endDate.Date)
            {
               return GetTodayRoomCount(hotelId,roomtype,beginDate,endDate);
            }

            DateTime startDate = beginDate.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            IList<RoomCount> roomCounts = new List<RoomCount>();

            while (endDate > startDate)
            {
                DateTime nextDate = startDate.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

                DateTime date = startDate;

                var occupies = GetCacheOccupies(hotelId, o => o.RoomTypeID == roomtype.RoomTypeID
                                                && o.StartDate < nextDate
                                                && o.EndDate > date
                                                && o.IsValid);

                var count = BuildRoomCount(occupies, roomtype, startDate);

                roomCounts.Add(count);
                
                startDate = startDate.AddDays(1);
            }

            int min = roomCounts.Min(o => o.OverResvUsableCount);

            var usableCount = roomCounts.FirstOrDefault(o => o.OverResvUsableCount == min);

            return usableCount;
        }

        private RoomCount GetTodayRoomCount(string hotelId,RoomType roomtype,DateTime beginDate,DateTime endDate)
        {
            var occupies = GetCacheOccupies(hotelId, o => o.RoomTypeID == roomtype.RoomTypeID
                                                 && o.StartDate < endDate
                                                 && o.EndDate > beginDate
                                                 && o.IsValid);

            var count = BuildRoomCount(occupies, roomtype, beginDate);

            return count;
        }
        
        int outOfOrderType = (int)OrderType.OutOfOrder;
        int repairType = (int)OrderType.RepairRoom;
        int resvType = (int)OrderType.Reserve;
        int checkInType = (int)OrderType.CheckIn;
        /// <summary>
        /// 装载房量统计
        /// </summary>
        private RoomCount BuildRoomCount(IEnumerable<RoomOccupy> occupies, RoomType roomtype, DateTime bizDay)
        {
            var count = new RoomCount();

            count.RoomTypeID = roomtype.RoomTypeID;

            count.RoomTypeName = roomtype.RoomTypeName;

            count.BizDay = bizDay.Date;

            //订单量
            count.OrderCount = occupies.Count(o => o.OrderType == resvType || o.OrderType == checkInType);

            //豁免量
            count.InvCount = occupies.Count(o => o.OrderType == outOfOrderType);

            //维修量
            count.RepairCount = occupies.Count(o => o.OrderType == repairType);

            //总房量
            count.Count = roomtype.TotalRooms;

            //有效房量
            count.ValidCount = roomtype.TotalRooms - count.InvCount;

            //占用量 = 订单量 + 维修量
            count.OccupyCount = count.OrderCount + count.RepairCount;

            //可用量 = 总有效房量 - 占用量
            count.UsableCount = count.ValidCount - count.OccupyCount ;

            //可超预订数
            count.WaitCount = roomtype.WaitRooms;

            //可超预订的可用总数
            count.OverResvUsableCount = count.ValidCount + count.WaitCount - count.OccupyCount;

            return count;

        }

        public RoomCount GetHotelAllCount(string hotelId, DateTime date)
        {
            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            DateTime beginDate = date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime endDate = date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId, exp);

            short allCount = (short)roomtypes.Sum(r => r.TotalRooms);

            var occupies = GetCacheOccupies(hotelId, o =>o.StartDate < endDate
                                            && o.EndDate > beginDate
                                            && o.OrderType == outOfOrderType
                                            && o.IsValid);

            RoomType roomtype = new RoomType() {RoomTypeID = "ALL", RoomTypeName = "全部房型" ,TotalRooms=allCount};
            
            return BuildRoomCount(occupies, roomtype, date);
        }

        /// <summary>
        /// 获取酒店实时运营状态
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypes"></param>
        /// <returns></returns>
        public IEnumerable<OperationState> GetOperationStatus(string hotelId, IList<RoomType> roomTypes)
        {
            IReserveRepository resRepository = container.Resolve<IReserveRepository>();

            DateTime bizDay = BizDay.Get(hotelId);

            var roomCache = RoomStatusCache.GetInstance();

            var priceCache = PriceCache.GetInstance();

            IEnumerable<OperationState> status = resRepository.GetOperationStatus(hotelId, roomTypes, bizDay);

            var occupies = GetCacheOccupies(hotelId, p => p.IsValid);

            int orderTypeI = (int)OrderType.CheckIn;

            //int orderTypeR = (int)OrderType.Reserve;

            string rsOD = EnumHelper.GetCode(RoomStatus.OD);

            string rsOC = EnumHelper.GetCode(RoomStatus.OC);

            DateTime startDate = bizDay.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime finalDate = bizDay.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

            foreach(RoomType roomType in roomTypes)
            {
                var state = status.FirstOrDefault(s => s.RoomTypeID == roomType.RoomTypeID);
                
                var rooms = roomCache.GetCacheRooms(GlobalConst.DEFAULT_START_TIME, hotelId,roomType.RoomTypeID);
                
                state.ODCount = rooms.Count(r => r.Status == rsOD );

                state.OCCount = rooms.Count(r =>r.Status == rsOC);
                
                state.TodayCheckIn = occupies.Count(o =>o.RoomTypeID==state.RoomTypeID&& o.StartDate.Date == bizDay && o.OrderType == orderTypeI);
                
                state.TodayBooking = occupies.Count(o =>o.RoomTypeID==state.RoomTypeID&& o.BookBizDay == bizDay);

                int overRoomCount = occupies.Count(o =>
                                                   o.RoomTypeID == state.RoomTypeID
                                                   && o.StartDate < finalDate
                                                   && o.EndDate > startDate
                                                   && o.IsValid) - roomType.TotalRooms;

                state.OverReseve = overRoomCount>0?overRoomCount:0;

                decimal normalPrice = priceCache.GetRoomPrice(hotelId, roomType.RoomTypeID, bizDay);

                FillCache(state, GetHotelState(hotelId, roomType, bizDay, rooms, occupies, normalPrice));

                state.TodayCheckOut = state.TodayLeave + state.WillLeave;//已离+将离
            }
            
            return status;
        }
        
        /// <summary>
        /// 获取酒店房间实时状态
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypes"></param>
        /// <returns></returns>
        public IEnumerable<RealTimeHotelState> GetRealTimeHotelStatus(string hotelId, IList<RoomType> roomTypes)
        {
            if(roomTypes==null||roomTypes.Count<=0)return null;

            DateTime bizDay = BizDay.Get(hotelId);

            var occupies = GetCacheOccupies(hotelId, p => p.IsValid);

            IList<RealTimeHotelState> status = new List<RealTimeHotelState>();

            var roomCache = RoomStatusCache.GetInstance();

            var priceCache = PriceCache.GetInstance();

            foreach( var item in roomTypes)
            {
                RoomType roomType = item;

                var rooms = roomCache.GetCacheRooms(GlobalConst.DEFAULT_START_TIME, hotelId,roomType.RoomTypeID);

                decimal normalPrice = priceCache.GetRoomPrice(hotelId, roomType.RoomTypeID, bizDay);

                RealTimeHotelState state = GetHotelState(hotelId, roomType, bizDay, rooms, occupies, normalPrice);

                status.Add(state);
            }
            
            return status;
        }
        
        /// <summary>
        /// 获取将到的房号
        /// </summary>
        /// <param name="hotelId"></param>
        /// <returns></returns>
        public IList<RoomOccupy> GetWillComeOccupy (string hotelId,DateTime modifyDate)
        {
            DateTime bizDay=BizDay.Get(hotelId);

            DateTime startDate = bizDay;

            DateTime EndDate = bizDay.AddDays(1).AddMinutes(-1);

            if(bizDay.Date!=DateTime.Today)
            {
                EndDate = DateTime.Today.AddDays(1).AddMinutes(-1);
            }

            var occupies = GetCacheOccupies(hotelId, r => r.IsValid && r.StartDate > startDate && r.StartDate < EndDate && r.ModifiedTime >= modifyDate);

            return occupies;
        }

        private RealTimeHotelState GetHotelState(string hotelId,RoomType roomtype,DateTime bizDay,IEnumerable<Room> rooms,IEnumerable<RoomOccupy> occupies,decimal normalPrice)
        {
            string rsVC = EnumHelper.GetCode(RoomStatus.VC);

            string rsVD = EnumHelper.GetCode(RoomStatus.VD);

            int orderTypeI = (int) OrderType.CheckIn;

            int orderTypeR = (int) OrderType.Reserve;

            int orderTypeRepair = (int) OrderType.RepairRoom;

            int orderTypeOOO = (int) OrderType.OutOfOrder;

            RealTimeHotelState state = new RealTimeHotelState();

            state.RoomTypeID = roomtype.RoomTypeID;

            state.RoomTypeName = roomtype.RoomTypeName;

            state.Totals = roomtype.TotalRooms;

            DateTime startDate = bizDay.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime finalDate = bizDay.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR );

            state.VacancyRoom = rooms.Count(r => r.Status == rsVC || r.Status == rsVD);

            state.CheckIn = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                && o.OrderType == orderTypeI);

            state.TodayWillCome = occupies.Count(o=>o.RoomTypeID==roomtype.RoomTypeID
                && o.OrderType==orderTypeR && o.StartDate.Date==bizDay);

            state.Repair = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                               && o.EndDate >= bizDay
                                               && o.StartDate.Date<=bizDay
                                               && o.OrderType == orderTypeRepair);

            state.OutOfOrder=occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                               && o.EndDate >= bizDay
                                               && o.StartDate.Date <= bizDay
                                               && o.OrderType == orderTypeOOO);

            state.Lock = rooms.Count(r =>
                                {
                                    var firstOrDefault = r.RoomAttribute.FirstOrDefault(a => a.AttributeCode == EnumHelper.GetCode(RoomAttributeCode.LR));
                                    return firstOrDefault != null && firstOrDefault.IsValid;
                                });

            state.WillLeave = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                  && o.EndDate.Date <= bizDay
                                                  && o.OrderType == orderTypeI);

            //查询房价
            state.NormalPrice = normalPrice;

            //总房量 + 可超数量  - 总占用量
            //state.UsableRoom = roomtype.TotalRooms - occupies.Count(o =>
            //                                                        o.RoomTypeID == roomtype.RoomTypeID
            //                                                        && o.StartDate < finalDate
            //                                                        && o.EndDate > startDate);

            //营业日可用量=（总房量-今日预抵-在住+今日将离）
            state.UsableRoom = state.Totals - state.TodayWillCome - state.CheckIn + state.WillLeave;

            //总预定量
            state.Reserve = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                && o.OrderType == orderTypeR);

            //预订排房数
            state.AssignReseve = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                     && o.StartDate < finalDate
                                                     && o.EndDate > startDate
                                                     && o.OrderType == orderTypeR
                                                     && !string.IsNullOrWhiteSpace(o.RoomNo));

            int validRooms = state.Totals - state.OutOfOrder;

            state.OccupancyRatePercent = "0.00%";

            if (validRooms > 0)
            {
                state.OccupancyRate = Math.Round((decimal)((double)state.CheckIn / validRooms ), 2);

                state.OccupancyRatePercent = state.OccupancyRate.ToString("P");
            }

            state.VCRooms = rooms.Count(r => r.Status == rsVC);

            state.VDRooms = rooms.Count(r => r.Status == rsVD);

            state.WaitRooms = roomtype.WaitRooms;

            return state;
        }
        
        private void FillCache(OperationState state, RealTimeHotelState hotelState)
        {
            state.AssignReseve = hotelState.AssignReseve;
            state.CheckIn= hotelState.CheckIn;
            state.Lock= hotelState.Lock;
            state.NormalPrice=hotelState.NormalPrice;
            state.OccupancyRate = hotelState.OccupancyRate;
            state.OccupancyRatePercent = hotelState.OccupancyRatePercent;
            state.OutOfOrder = hotelState.OutOfOrder;
            state.Repair= hotelState.Repair;
            state.Reserve = hotelState.Reserve;
            state.TodayWillCome = hotelState.TodayWillCome;
            state.Totals = hotelState.Totals;
            state.UsableRoom = hotelState.UsableRoom;
            state.VacancyRoom= hotelState.VacancyRoom;
            state.VCRooms= hotelState.VCRooms;
            state.VDRooms= hotelState.VDRooms;
            state.WillLeave = hotelState.WillLeave;
            state.WaitRooms = hotelState.WaitRooms;
        }

        #endregion           

    }

    /// <summary>
    /// 房量缓存处理中心
    /// <para>--------------------------</para>
    /// <para>@Author: cnalexi@gmail.com</para> 
    /// <para>@Create: 2012/3/31</para>  
    /// </summary>
    public class RoomCountCacheTest
    {
        #region ☆ -------- 初始化做预备 -------- ☆

        /// <summary>
        /// 需要更新房量的队列 string：hotelId,Datetime:更新版本时间
        /// </summary>
        private IDictionary<string, DateTime> _updateQueue = new Dictionary<string, DateTime>();

        /// <summary>
        /// 房量缓存调整
        /// </summary>
        private IDictionary<string, IDictionary<string, RoomOccupy>> _hotelOccupies =new Dictionary<string, IDictionary<string, RoomOccupy>>();

        /// <summary>
        /// string:orderId
        /// </summary>
        private IDictionary<string, RoomOccupy> _occupyCache = new Dictionary<string,  RoomOccupy>();
        
        private static volatile RoomCountCacheTest _instance;

        private static readonly object _lock = new object();

        /// <summary>
        /// 抢救数据间隔秒数
        /// </summary>
        public const int RESCUE_CYCLE=10; 
        
        private RoomCountCacheTest(){}

        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        private ReadonlyDictionary<string, RoomOccupy> _readonlyRoomOccupies;

        /// <summary>
        /// 酒店默认入住时间[需做成可配置]
        /// </summary>
        private const int DEFAULT_STARTDATE_HOUR = 23;
        /// <summary>
        /// 酒店默认退房时间[需做成可配置]
        /// </summary>
        private const int DEFAULT_ENDDATE_HOUR = 12;

        public static RoomCountCacheTest GetInstance()
        {
            if(_instance==null)
            {
                lock(_lock)
                {
                    if(_instance==null)
                    {
                        var rcc = new RoomCountCacheTest();

                        rcc.InitCache();

                        _instance = rcc;

                        Thread.MemoryBarrier();
                    }
                }
            }
            return _instance;
        }

        #endregion

        #region ☆ -------- 内部处理过程 -------- ☆

        private void InitCache()
        {
            IRoomOccupyRepository roomOccupyRepository = container.Resolve<IRoomOccupyRepository>();
            
            var connections = DbContextService.GetAllConnectionString();

            try
            {
                foreach (var conn in connections)
                {
                    IList<RoomOccupy> occupies = null;

                    var transactionOptions = new System.Transactions.TransactionOptions();

                    transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

                    using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                    {
                        occupies = roomOccupyRepository.GetAllRoomOccupies(conn);

                        scope.Complete();
                    }

                    if (occupies != null && occupies.Count>0)
                    {
                        DateTime versionTime = occupies.Max(o => o.ModifiedTime);

                        _updateQueue.Add(conn, versionTime);

                        FillCache(occupies);
                    }

                }
            }catch(Exception error)
            {
                OperateLog.ErrorLog(DateTime.Now + "房量缓存初始化失败" + error);
            }
        }
        
        private void FillCache(IList<RoomOccupy> occupies)
        {
            foreach(var occupy in occupies)
            {
                if(_occupyCache.ContainsKey(occupy.OrderId))
                {
                    _occupyCache.Remove(occupy.OrderId);
                }

                if (occupy.IsValid)
                {
                    _occupyCache.Add(occupy.OrderId, occupy);
                }
            }

            var readonlyOccupies = new ReadonlyDictionary<string, RoomOccupy>(_occupyCache);

            _readonlyRoomOccupies = readonlyOccupies;
        }

        public void Refresh()
        {
            //System.Diagnostics.Debug.WriteLine("刷新房量:" + DateTime.Now.ToString());
            try
            {
                BuildCache(null);

            }catch(Exception error)
            {

                OperateLog.ErrorLog(DateTime.Now + "房量缓存刷新失败", error);
                
            }
        }

        public void Rescue(int seconds)
        {
            //System.Diagnostics.Debug.WriteLine("修正房量:" + DateTime.Now.ToString());
            try
            {
                BuildCache(DateTime.Now.AddSeconds(seconds));

            }catch(Exception error)
            {

                OperateLog.ErrorLog(DateTime.Now + "房量缓存修正失败", error);
            }

        }

        private void BuildCache(DateTime? time)
        {
            IRoomOccupyRepository roomOccupyRepository = container.Resolve<IRoomOccupyRepository>();
            
            var keys= _updateQueue.Select(o => o.Key).ToList();
            
            foreach (var key in keys)
            {
                DateTime versionTime = time ?? _updateQueue[key];

                Expression<Func<RoomOccupy, bool>> exp = r => r.ModifiedTime > versionTime;
                //分库读取所有有效房控信息
                IList<RoomOccupy> occupies = null;

                var transactionOptions = new System.Transactions.TransactionOptions();

                transactionOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;

                using (var scope = new System.Transactions.TransactionScope(System.Transactions.TransactionScopeOption.Required, transactionOptions))
                {
                    occupies =roomOccupyRepository.GetRoomOccupies(key, exp);

                    scope.Complete();
                }

                if (occupies != null && occupies.Count > 0)
                {
                    FillCache(occupies);

                    _updateQueue[key] = occupies.Max(r => r.ModifiedTime);
                }
            }
        }
        
        #endregion

        #region ☆ -------- 外部调用服务 -------- ☆



        public IDictionary<string, RoomOccupy> RoomOccupies
        {
            get
            {
                if (_readonlyRoomOccupies == null)
                    _readonlyRoomOccupies =
                        new ReadonlyDictionary<string, RoomOccupy>(new Dictionary<string, RoomOccupy>());

                return _readonlyRoomOccupies;
            }
        }

        /// <summary>
        /// 获取缓存房控
        /// </summary>
        /// <param name="predicate"></param>
        /// <returns></returns>
        private IList<RoomOccupy> GetCacheOccupies(Func<RoomOccupy,bool> predicate)
        {
            if (_readonlyRoomOccupies == null)return new List<RoomOccupy>();

            var occupies = _readonlyRoomOccupies.Values.Where(predicate).ToList();

            return occupies;
        }


        /// <summary>
        /// 获取一段时间内酒店所有房型的详细房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public Dictionary<DateTime, IEnumerable<RoomCount>> GetHotelRoomCount(string hotelId, DateTime beginDate, DateTime endDate)
        {
            if(beginDate>endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }

            DateTime startDate = beginDate.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId,exp);

            Dictionary<DateTime, IEnumerable<RoomCount>> hotelRoomCount =new Dictionary<DateTime, IEnumerable<RoomCount>>();
            
            while(endDate>startDate)
            {
                IList<RoomCount> counts = new List<RoomCount>();

                DateTime nextDate = startDate.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

                #region 填充房量

                foreach (var item in roomtypes)
                {
                    RoomType roomtype = item;

                    DateTime date = startDate;

                    var occupies = GetCacheOccupies(o =>
                                                    o.HotelID == hotelId
                                                    && o.RoomTypeID == roomtype.RoomTypeID
                                                    && o.StartDate < nextDate
                                                    && o.EndDate > date
                                                    && o.IsValid);

                    var count = BuildRoomCount(occupies, roomtype,startDate);

                    counts.Add(count);
                }

                #endregion

                hotelRoomCount.Add(startDate.Date, counts);

                startDate = startDate.AddDays(1);
            }

            return hotelRoomCount;
        }

        /// <summary>
        /// 获取一段时间内酒店所有房型大致可用房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public IEnumerable<RoomCount> GetUsableRoomCount(string hotelId,DateTime beginDate,DateTime endDate)
        {
            if (beginDate > endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }

            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId, exp);
            
            IList<RoomCount> counts = new List<RoomCount>();

            foreach (var item in roomtypes)
            {
                RoomType roomType = item;

                var count = GetRoomTypeCount(hotelId, roomType, beginDate, endDate);

                counts.Add(count);
            }

            return counts;
        }

        /// <summary>
        /// 获取一段时间内酒店某种房型可用房量
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypeId"></param>
        /// <param name="beginDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public RoomCount GetRoomCount(string hotelId,string roomTypeId,DateTime beginDate,DateTime endDate)
        {
            if (beginDate > endDate)
            {
                throw new ArgumentException(string.Format("获取房量开始时间{0}>结束时间{1},请检查日期", beginDate.ToString(), endDate.ToString()));
            }
            
            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            RoomType roomtype = repositoryRoomTypes.Find(hotelId, hotelId, roomTypeId);

            return GetRoomTypeCount(hotelId, roomtype, beginDate, endDate);

        }

        private RoomCount GetRoomTypeCount(string hotelId, RoomType roomtype, DateTime beginDate, DateTime endDate)
        {
            if (beginDate.Date == endDate.Date)
            {
               return GetTodayRoomCount(hotelId,roomtype,beginDate,endDate);
            }

            DateTime startDate = beginDate.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            IList<RoomCount> roomCounts = new List<RoomCount>();

            while (endDate > startDate)
            {
                DateTime nextDate = startDate.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

                DateTime date = startDate;

                var occupies = GetCacheOccupies(o =>
                                                o.HotelID == hotelId
                                                && o.RoomTypeID == roomtype.RoomTypeID
                                                && o.StartDate < nextDate
                                                && o.EndDate > date
                                                && o.IsValid);

                var count = BuildRoomCount(occupies, roomtype, startDate);

                roomCounts.Add(count);
                
                startDate = startDate.AddDays(1);
            }

            int min = roomCounts.Min(o => o.OverResvUsableCount);

            var usableCount = roomCounts.FirstOrDefault(o => o.OverResvUsableCount == min);

            return usableCount;
        }

        private RoomCount GetTodayRoomCount(string hotelId,RoomType roomtype,DateTime beginDate,DateTime endDate)
        {
            var occupies = GetCacheOccupies(o => o.HotelID == hotelId
                                                 && o.RoomTypeID == roomtype.RoomTypeID
                                                 && o.StartDate < endDate
                                                 && o.EndDate > beginDate
                                                 && o.IsValid);

            var count = BuildRoomCount(occupies, roomtype, beginDate);

            return count;
        }


        int outOfOrderType = (int)OrderType.OutOfOrder;
        int repairType = (int)OrderType.RepairRoom;
        int resvType = (int)OrderType.Reserve;
        int checkInType = (int)OrderType.CheckIn;
        /// <summary>
        /// 装载房量统计
        /// </summary>
        private RoomCount BuildRoomCount(IEnumerable<RoomOccupy> occupies, RoomType roomtype, DateTime bizDay)
        {
            var count = new RoomCount();

            count.RoomTypeID = roomtype.RoomTypeID;

            count.RoomTypeName = roomtype.RoomTypeName;

            count.BizDay = bizDay.Date;

            //订单量
            count.OrderCount = occupies.Count(o => o.OrderType == resvType || o.OrderType == checkInType);

            //豁免量
            count.InvCount = occupies.Count(o => o.OrderType == outOfOrderType);

            //维修量
            count.RepairCount = occupies.Count(o => o.OrderType == repairType);

            //总房量
            count.Count = roomtype.TotalRooms;

            //有效房量
            count.ValidCount = roomtype.TotalRooms - count.InvCount;

            //占用量 = 订单量 + 维修量
            count.OccupyCount = count.OrderCount + count.RepairCount;

            //可用量 = 总有效房量 - 占用量
            count.UsableCount = count.ValidCount - count.OccupyCount ;

            //可超预订数
            count.WaitCount = roomtype.WaitRooms;

            //可超预订的可用总数
            count.OverResvUsableCount = count.ValidCount + count.WaitCount - count.OccupyCount;

            return count;

        }

        public RoomCount GetHotelAllCount(string hotelId, DateTime date)
        {
            IRoomTypeRepository repositoryRoomTypes = container.Resolve<IRoomTypeRepository>();

            DateTime beginDate = date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime endDate = date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

            Expression<Func<RoomType, bool>> exp = r => r.HotelID == hotelId && r.IsValid == true;

            IEnumerable<RoomType> roomtypes = repositoryRoomTypes.BatchFind(hotelId, exp);

            short allCount = (short)roomtypes.Sum(r => r.TotalRooms);

            var occupies = GetCacheOccupies(o =>
                                            o.HotelID == hotelId
                                            && o.StartDate < endDate
                                            && o.EndDate > beginDate
                                            && o.OrderType == outOfOrderType
                                            && o.IsValid);

            RoomType roomtype = new RoomType() {RoomTypeID = "ALL", RoomTypeName = "全部房型" ,TotalRooms=allCount};
            
            return BuildRoomCount(occupies, roomtype, date);
        }

        /// <summary>
        /// 获取酒店实时运营状态
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypes"></param>
        /// <returns></returns>
        public IEnumerable<OperationState> GetOperationStatus(string hotelId, IList<RoomType> roomTypes)
        {
            IReserveRepository resRepository = container.Resolve<IReserveRepository>();

            DateTime bizDay = BizDay.Get(hotelId);

            var roomCache = RoomStatusCache.GetInstance();

            var priceCache = PriceCache.GetInstance();

            IEnumerable<OperationState> status = resRepository.GetOperationStatus(hotelId, roomTypes, bizDay);

            var occupies = GetCacheOccupies(p => p.HotelID == hotelId&&p.IsValid);

            int orderTypeI = (int)OrderType.CheckIn;

            //int orderTypeR = (int)OrderType.Reserve;

            string rsOD = EnumHelper.GetCode(RoomStatus.OD);

            string rsOC = EnumHelper.GetCode(RoomStatus.OC);

            DateTime startDate = bizDay.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime finalDate = bizDay.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR);

            foreach(RoomType roomType in roomTypes)
            {
                var state = status.FirstOrDefault(s => s.RoomTypeID == roomType.RoomTypeID);
                
                var rooms = roomCache.GetCacheRooms(GlobalConst.DEFAULT_START_TIME, hotelId,roomType.RoomTypeID);
                
                state.ODCount = rooms.Count(r => r.Status == rsOD );

                state.OCCount = rooms.Count(r =>r.Status == rsOC);
                
                state.TodayCheckIn = occupies.Count(o =>o.RoomTypeID==state.RoomTypeID&& o.StartDate.Date == bizDay && o.OrderType == orderTypeI);
                
                state.TodayBooking = occupies.Count(o =>o.RoomTypeID==state.RoomTypeID&& o.BookBizDay == bizDay);

                int overRoomCount = occupies.Count(o =>
                                                   o.RoomTypeID == state.RoomTypeID
                                                   && o.StartDate < finalDate
                                                   && o.EndDate > startDate
                                                   && o.IsValid) - roomType.TotalRooms;

                state.OverReseve = overRoomCount>0?overRoomCount:0;

                decimal normalPrice = priceCache.GetRoomPrice(hotelId, roomType.RoomTypeID, bizDay);

                FillCache(state, GetHotelState(hotelId, roomType, bizDay, rooms, occupies, normalPrice));

                state.TodayCheckOut = state.TodayLeave + state.WillLeave;//已离+将离
            }
            
            return status;
        }
        
        /// <summary>
        /// 获取酒店房间实时状态
        /// </summary>
        /// <param name="hotelId"></param>
        /// <param name="roomTypes"></param>
        /// <returns></returns>
        public IEnumerable<RealTimeHotelState> GetRealTimeHotelStatus(string hotelId, IList<RoomType> roomTypes)
        {
            if(roomTypes==null||roomTypes.Count<=0)return null;

            DateTime bizDay = BizDay.Get(hotelId);

            var occupies = GetCacheOccupies(p => p.HotelID == hotelId && p.IsValid);

            IList<RealTimeHotelState> status = new List<RealTimeHotelState>();

            var roomCache = RoomStatusCache.GetInstance();

            var priceCache = PriceCache.GetInstance();

            foreach( var item in roomTypes)
            {
                RoomType roomType = item;

                var rooms = roomCache.GetCacheRooms(GlobalConst.DEFAULT_START_TIME, hotelId,roomType.RoomTypeID);

                decimal normalPrice = priceCache.GetRoomPrice(hotelId, roomType.RoomTypeID, bizDay);

                RealTimeHotelState state = GetHotelState(hotelId, roomType, bizDay, rooms, occupies, normalPrice);

                status.Add(state);
            }
            
            return status;
        }
        
        /// <summary>
        /// 获取将到的房号
        /// </summary>
        /// <param name="hotelId"></param>
        /// <returns></returns>
        public IList<RoomOccupy> GetWillComeOccupy (string hotelId,DateTime modifyDate)
        {
            DateTime bizDay=BizDay.Get(hotelId);

            DateTime startDate = bizDay;

            DateTime EndDate = bizDay.AddDays(1).AddMinutes(-1);

            if(bizDay.Date!=DateTime.Today)
            {
                EndDate = DateTime.Today.AddDays(1).AddMinutes(-1);
            }

            var occupies = GetCacheOccupies(r => r.HotelID == hotelId && r.IsValid == true && r.StartDate > startDate && r.StartDate < EndDate && r.ModifiedTime >= modifyDate);

            return occupies;
        }

        private RealTimeHotelState GetHotelState(string hotelId,RoomType roomtype,DateTime bizDay,IEnumerable<Room> rooms,IEnumerable<RoomOccupy> occupies,decimal normalPrice)
        {
            string rsVC = EnumHelper.GetCode(RoomStatus.VC);

            string rsVD = EnumHelper.GetCode(RoomStatus.VD);

            int orderTypeI = (int) OrderType.CheckIn;

            int orderTypeR = (int) OrderType.Reserve;

            int orderTypeRepair = (int) OrderType.RepairRoom;

            int orderTypeOOO = (int) OrderType.OutOfOrder;

            RealTimeHotelState state = new RealTimeHotelState();

            state.RoomTypeID = roomtype.RoomTypeID;

            state.RoomTypeName = roomtype.RoomTypeName;

            state.Totals = roomtype.TotalRooms;

            DateTime startDate = bizDay.Date.AddHours(DEFAULT_STARTDATE_HOUR);

            DateTime finalDate = bizDay.Date.AddDays(1).AddHours(DEFAULT_ENDDATE_HOUR );

            state.VacancyRoom = rooms.Count(r => r.Status == rsVC || r.Status == rsVD);

            state.CheckIn = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                && o.OrderType == orderTypeI);

            state.TodayWillCome = occupies.Count(o=>o.RoomTypeID==roomtype.RoomTypeID
                && o.OrderType==orderTypeR && o.StartDate.Date==bizDay);

            state.Repair = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                               && o.EndDate >= bizDay
                                               && o.StartDate.Date<=bizDay
                                               && o.OrderType == orderTypeRepair);

            state.OutOfOrder=occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                               && o.EndDate >= bizDay
                                               && o.StartDate.Date <= bizDay
                                               && o.OrderType == orderTypeOOO);

            state.Lock = rooms.Count(r =>
                                {
                                    var firstOrDefault = r.RoomAttribute.FirstOrDefault(a => a.AttributeCode == EnumHelper.GetCode(RoomAttributeCode.LR));
                                    return firstOrDefault != null && firstOrDefault.IsValid;
                                });

            state.WillLeave = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                  && o.EndDate.Date <= bizDay
                                                  && o.OrderType == orderTypeI);

            //查询房价
            state.NormalPrice = normalPrice;

            //总房量 + 可超数量  - 总占用量
            //state.UsableRoom = roomtype.TotalRooms - occupies.Count(o =>
            //                                                        o.RoomTypeID == roomtype.RoomTypeID
            //                                                        && o.StartDate < finalDate
            //                                                        && o.EndDate > startDate);

            //营业日可用量=（总房量-今日预抵-在住+今日将离）
            state.UsableRoom = state.Totals - state.TodayWillCome - state.CheckIn + state.WillLeave;

            //总预定量
            state.Reserve = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                && o.OrderType == orderTypeR);

            //预订排房数
            state.AssignReseve = occupies.Count(o => o.RoomTypeID == roomtype.RoomTypeID
                                                     && o.StartDate < finalDate
                                                     && o.EndDate > startDate
                                                     && o.OrderType == orderTypeR
                                                     && !string.IsNullOrWhiteSpace(o.RoomNo));

            int validRooms = state.Totals - state.OutOfOrder;

            state.OccupancyRatePercent = "0.00%";

            if (validRooms > 0)
            {
                state.OccupancyRate = Math.Round((decimal)((double)state.CheckIn / validRooms ), 2);

                state.OccupancyRatePercent = state.OccupancyRate.ToString("P");
            }

            state.VCRooms = rooms.Count(r => r.Status == rsVC);

            state.VDRooms = rooms.Count(r => r.Status == rsVD);

            state.WaitRooms = roomtype.WaitRooms;

            return state;
        }
        
        private void FillCache(OperationState state, RealTimeHotelState hotelState)
        {
            state.AssignReseve = hotelState.AssignReseve;
            state.CheckIn= hotelState.CheckIn;
            state.Lock= hotelState.Lock;
            state.NormalPrice=hotelState.NormalPrice;
            state.OccupancyRate = hotelState.OccupancyRate;
            state.OccupancyRatePercent = hotelState.OccupancyRatePercent;
            state.OutOfOrder = hotelState.OutOfOrder;
            state.Repair= hotelState.Repair;
            state.Reserve = hotelState.Reserve;
            state.TodayWillCome = hotelState.TodayWillCome;
            state.Totals = hotelState.Totals;
            state.UsableRoom = hotelState.UsableRoom;
            state.VacancyRoom= hotelState.VacancyRoom;
            state.VCRooms= hotelState.VCRooms;
            state.VDRooms= hotelState.VDRooms;
            state.WillLeave = hotelState.WillLeave;
            state.WaitRooms = hotelState.WaitRooms;
        }

        #endregion

        
    }
    
}
